package com.justgame.project.cloud.common;

import com.justgame.project.cloud.common.constant.NacosConstant;
import com.justgame.project.cloud.common.launch.LauncherService;
import com.justgame.project.cloud.common.util.HttpContextUtil;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.*;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 *
 * @author ZhouWeiBo
 * @create 2022/4/25
 */
public class DataTurbineApplication {

    public DataTurbineApplication() {
    }

    public static ConfigurableApplicationContext run(String appName, Class source, String... args) {
        SpringApplicationBuilder builder = createSpringApplicationBuilder(appName, source, args);
        return builder.run(args);
    }

    public static SpringApplicationBuilder createSpringApplicationBuilder(String appName, Class source, String... args) {
        Assert.hasText(appName, "[appName]服务名不能为空");
        ConfigurableEnvironment environment = new StandardEnvironment();
        MutablePropertySources propertySources = environment.getPropertySources();
        propertySources.addFirst(new SimpleCommandLinePropertySource(args));
        propertySources.addLast(new MapPropertySource("systemProperties", environment.getSystemProperties()));
        propertySources.addLast(new SystemEnvironmentPropertySource("systemEnvironment", environment.getSystemEnvironment()));
        String[] activeProfiles = environment.getActiveProfiles();
        List<String> profiles = Arrays.asList(activeProfiles);
        List<String> presetProfiles = new ArrayList<>(Arrays.asList("dev", "test", "prod"));
        presetProfiles.retainAll(profiles);
        List<String> activeProfileList = new ArrayList<>(profiles);
        Function<Object[], String> joinFun = StringUtils::arrayToCommaDelimitedString;
        SpringApplicationBuilder builder = new SpringApplicationBuilder(source);
        String profile;
        if (activeProfileList.isEmpty()) {
            profile = "dev";
            activeProfileList.add(profile);
            builder.profiles(profile);
        } else {
            if (activeProfileList.size() != 1) {
                throw new RuntimeException("同时存在环境变量:[" + StringUtils.arrayToCommaDelimitedString(activeProfiles) + "]");
            }

            profile = (String)activeProfileList.get(0);
        }
        String startJarPath = DataTurbineApplication.class.getResource("/").getPath().split("!")[0];
        String activePros = (String)joinFun.apply(activeProfileList.toArray());
        System.out.printf("----Running... 环境变量:[%s]，jar地址:[%s]----%n", activePros, startJarPath);
        Properties props = System.getProperties();
        props.setProperty("spring.application.name", appName);
        props.setProperty("spring.profiles.active", profile);
        props.setProperty("info.version", "v1.0");
        props.setProperty("info.desc", appName);
        props.setProperty("file.encoding", StandardCharsets.UTF_8.name());
        /*
         * # MyBatis Plus通用配置
         * mybatis-plus:
         *   mapper-locations: classpath:static/mapper/*.xml
         *   configuration:
         *     log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
         *     map-underscore-to-camel-case: true
         *   db-config:
         *     logic-delete-value: 1 #逻辑删除后的值（默认为1）
         *     logic-not-delete-value: 0 #未删除的值（默认为0）
         */
        props.setProperty("mybatis-plus.mapper-locations","classpath:static/mapper/*.xml");
        props.setProperty("mybatis-plus.configuration.log-impl","org.apache.ibatis.logging.stdout.StdOutImpl");
        props.setProperty("mybatis-plus.configuration.map-underscore-to-camel-case","true");
//        props.setProperty("mybatis-plus.configuration.type-handlers-package","com.justgame.project.cloud.base.config");
        props.setProperty("mybatis-plus.db-config.logic-delete-value","1"); // 逻辑删除后的值（默认为1）
        props.setProperty("mybatis-plus.db-config.logic-not-delete-value","0"); // 未删除的值（默认为0）
        /*
         * Feign配置
         * feign:
         *   circuitbreaker:
         *     enabled: true
         */
        props.setProperty("feign.circuitbreaker.enabled","true");
        props.setProperty("feign.okhttp.enabled","true");
        props.setProperty("feign.httpclient.enabled","false");

        props.setProperty("spring.servlet.multipart.max-request-size","256MB");
        props.setProperty("spring.servlet.multipart.max-file-size","256MB");
        props.setProperty("spring.main.allow-bean-definition-overriding", "true");
        props.setProperty("spring.cloud.nacos.config.file-extension", "yaml");
        props.setProperty("spring.cloud.nacos.config.shared-configs[0].data-id", NacosConstant.sharedDataId());
        props.setProperty("spring.cloud.nacos.config.shared-configs[0].group", "DEFAULT_GROUP");
        props.setProperty("spring.cloud.nacos.config.shared-configs[0].refresh", "true");
        props.setProperty("spring.cloud.nacos.config.shared-configs[1].data-id", NacosConstant.sharedDataId(profile));
        props.setProperty("spring.cloud.nacos.config.shared-configs[1].group", "DEFAULT_GROUP");
        props.setProperty("spring.cloud.nacos.config.shared-configs[1].refresh", "true");

        props.setProperty("spring.cloud.nacos.discovery.server-addr", NacosConstant.getNacosAddrs(activePros));
        props.setProperty("spring.cloud.nacos.config.server-addr",NacosConstant.getNacosAddrs(activePros));
        props.setProperty("spring.cloud.nacos.server-addr",NacosConstant.getNacosAddrs(activePros));

        /* 启用公网IP调用微服务，如不需要则注释掉下面配置！ */
        if ("prod".equals(profile)){
            String ipv4 = HttpContextUtil.getPublicIP().replaceAll(" ","");
            if (!StringUtils.isEmpty(ipv4)){
                props.setProperty("spring.cloud.nacos.discovery.ip",ipv4);
                props.setProperty("spring.cloud.nacos.discovery.network-interface", "eth0");
            }
        }



        builder.properties(props);

        List<LauncherService> launcherList = new ArrayList();
        ServiceLoader.load(LauncherService.class).forEach(launcherList::add);
        (launcherList.stream()
                .sorted(Comparator.comparing(LauncherService::getOrder))
                .collect(Collectors.toList()))
                .forEach((launcherService) -> {
                    launcherService.launcher(builder, appName, profile, isLocalDev());
                });
        return builder;
    }

    public static boolean isLocalDev() {
        String osName = System.getProperty("os.name");
        return StringUtils.hasText(osName) && !"LINUX".equalsIgnoreCase(osName);
    }
}
